package org.mparts.server.utils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

import org.mparts.server.EMF;
import org.mparts.server.domain.EntityBase;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.ibm.icu.impl.USerializedSet;

public class PersistUtils {

	public static final ThreadLocal<EntityManager> MANAGERS = new ThreadLocal<EntityManager>();
	
	private static Logger log = Logger.getLogger(PersistUtils.class.getName());

	private static String MANAGER = "sales@avtoimpuls.com";

	private PersistUtils() {
		// utils uses static methods
	}

	public static EntityManager getEntityManager() {
		EntityManager mgr = MANAGERS.get();
		// if manager is null assume we are not running in a web context
		if (mgr == null) {
			mgr = EMF.get().createEntityManager();
			MANAGERS.set(mgr);
			return mgr;
		}
		return MANAGERS.get();
	}

	public static void persistObject(Serializable e) {
		EntityManager mgr = getEntityManager();
		try {
			mgr.getTransaction().begin();
			mgr.persist(e);
			mgr.getTransaction().commit();
		} finally {
//			mgr.close();
		}
	}

	public static void mergeObject(EntityBase e) {
		try {
			mergeObject(e, true);
		} catch (Exception ex) {
			EntityManager mgr = getEntityManager();
			if ( mgr.getTransaction().isActive() ) {
				try {
					mgr.getTransaction().rollback();
				} catch (Exception e2) {
					log.log(Level.SEVERE, "transaction rollback failed", e2);
				}
			}
//			log.severe("merge object fail");
			log.log(Level.SEVERE, "merge object fail", ex);
//			mgr.close();
		}
	}

	public static <T extends EntityBase> T mergeObject(T e, boolean createTransaction) {
		EntityManager mgr = getEntityManager();
		T result = null;
		try {
			log.log(Level.INFO, "start merging object: {0}", e.toString());
			if (createTransaction) {
				mgr.getTransaction().begin();
			}
			result = mgr.merge(e);
			if (createTransaction) {
				mgr.getTransaction().commit();
			}
		} catch (Exception ex) {
//			if ( mgr.getTransaction().isActive() ) {
//				try {
//					mgr.getTransaction().rollback();
//				} catch (Exception e2) {
//					log.log(Level.SEVERE, "transaction rollback failed", e2);
//				}
//			}
//			log.severe("merge object fail");
			log.log(Level.SEVERE, "merge object fail", ex);
			throw new PersistenceException("Merge object fail", ex);
//			mgr.close();
		}
		return result;
	}

	public static void removeObject(EntityBase e) {
		try {
		removeObject(e, true);
		} catch (Exception ex) {
			EntityManager mgr = getEntityManager();		
			if ( mgr.getTransaction().isActive() ) {
				try {
					mgr.getTransaction().rollback();
				} catch (Exception e2) {
					log.log(Level.SEVERE, "transaction rollback failed", e2);
				}
			}
//			log.severe("remove object fail");
			log.log(Level.SEVERE, "remove object fail", ex);
//			mgr.close();
		}
	}
	
	public static void removeObject(EntityBase e, boolean createTransaction) {
		EntityManager mgr = getEntityManager();		
		try {
			log.log(Level.INFO, "start remove object: {0}", e.toString());
			if (createTransaction) {
				mgr.getTransaction().begin();
			}
			e = mgr.merge(e);
			mgr.remove(e);
			if (createTransaction) {
				mgr.getTransaction().commit();
			}
		} catch (Exception ex) {
//			if ( mgr.getTransaction().isActive() ) {
//				try {
//					mgr.getTransaction().rollback();
//				} catch (Exception e2) {
//					log.log(Level.SEVERE, "transaction rollback failed", e2);
//				}
//			}
//			log.severe("remove object fail");
			log.log(Level.SEVERE, "remove object fail", ex);
			throw new PersistenceException("Remove object fail", ex);
//			mgr.close();
		}
	}
	
	public static void startTransaction() {
		EntityManager mgr = getEntityManager();
		if ( mgr != null && !mgr.getTransaction().isActive() ) {
			mgr.getTransaction().begin();
		}
	}
	
	public static void rollbackTransaction() {
		EntityManager mgr = getEntityManager();
		if ( mgr != null && mgr.getTransaction().isActive() ) {
			mgr.getTransaction().rollback();
		}
	}
	
	public static void commitTransaction() {
		EntityManager mgr = getEntityManager();
		if ( mgr != null && mgr.getTransaction().isActive() ) {
			mgr.getTransaction().commit();
		}
	}
	
	public static List<String> getUserInfo(String url) {
		String userName = "";
		String loginUrl = "";
		String logoutUrl = "";
		String allowManage = "";
		UserService userService = UserServiceFactory.getUserService();
		if (userService != null) {
			if ( userService.isUserLoggedIn() ) {
				userName = userService.getCurrentUser().getNickname();
				log.warning("current user is " + userName);
				if (userService.isUserAdmin() || MANAGER.equals(userName) ) {
					allowManage = "1";
				}
			} else {
				loginUrl = userService.createLoginURL(url);
				log.warning("user is not logged");
			}
			logoutUrl = userService.createLogoutURL(url);
		} else {
			log.warning("user service is NULL");
		}
		ArrayList<String> list = new ArrayList<String>();
		list.add(userName);
		list.add(loginUrl);
		list.add(logoutUrl);
		list.add(allowManage);
		return list;
	}
	
	public static boolean isUserManager() {
		List<String> userInfo = getUserInfo("");
		if (userInfo != null && userInfo.size() >= 4) {
			return ("1".equals(userInfo.get(3)));
		} else {
			return false;
		}
	}

}
